#ifndef XGE_XWORKER_H_
#define XGE_XWORKER_H_
#include "xge_common_config.h"

#include "xthread.h"
#include "xthread_delegate.h"
#include "xthread_manager.h"
#include "xworker_queue.h"
#include "xtask.h"


namespace xge{
namespace xge_internal{

  // Query the CPU core number in order to decide the number of thread within a process
  // If the CPU support the HyperThread , that means a core can run 2 physical thread 
  // so this will switch the Core Value
  // Like Intel i7 Core has 6 core , but it will return 6*2 = 12 core since it can physically
  // run 12 thread concurrent 
  // However that does not mean We will take advantage of this 
  size_t QueryCPUCoreNumber() ;
  // Worker class provide ways to manipulate the queue stuff and
  // the thread thing .
  template < typename QueueType >
  class Worker : public Allocator {
  public:
    QueueType* GetQueuePtr() const {
      XASSERT( !thread_handler_ptr_.Null() );
      return queue_type_.Get();
    }
  public:
    // Push the task here 
    void PushTask( const TaskPtr& task , bool delay );
    void Sync() {
      thread_handler_ptr_->PushTask( &task_cache_ );
      task_cache_.clear();
    }
    // The controller stuff 
    bool Destroy( bool post_quit_soon , bool blocking );
    const TripleResult Wait( size_t ms );
    const TripleResult Wait();
    // Dispatch will allocate the internal thread object and
    // the thread_queue object internally and make it running
    // If you have really destroy the queue :
    // Destroy( true , true ); or 
    // Destroy( false, false); Wait();
    // the queue can be dispatched again , otherwise the dispatch
    // will refuse to do so !
    bool Dispatch( const String& thread_name , const char* debug_name );
    bool HasPostDestroyRequest() const {
      return has_post_destroy_request_;
    }
    Worker():has_post_destroy_request_(false){}
    ~Worker();
  private:
    typedef SharedPtr< QueueType , DefaultDestructor<QueueType> > QueueTypePtr;
    class WorkerThread : public ThreadDelegate {
    public:
      virtual void ThreadMain() {
        queue_type_->Loop();
      }
      WorkerThread( const QueueTypePtr& ptr ):queue_type_(ptr){}
      void set_queue_type( const QueueTypePtr& ptr ) {
        queue_type_ = ptr;
      }
      void Clear() {
        // deleted the queue type here
        queue_type_.Reset();
      }
      bool Empty() const {
        return queue_type_.Null();
      }
    private:
      QueueTypePtr queue_type_;
    };
    QueueTypePtr queue_type_;
    ThreadDelegatePtr delegate_ptr_;
    ThreadHandlerPtr thread_handler_ptr_;
    // using this to indicate that a post destroy request has been posted
    bool has_post_destroy_request_ ;
    // local task container 
    typedef WorkerQueue::TaskPtrList TaskLocalCacheList;
    // the task inside of this cache is used to locally identify 
    TaskLocalCacheList task_cache_ ;
  };

  template < typename QueueType >
  bool Worker<QueueType>::Dispatch( const String& thread_name , const char* debug_name ) {
    // We only create the class as the queue_type is empty 
    // which means the thread has exited successfully and
    // memory has been cleared 
    if( !queue_type_.Null() ) 
      return false;
    // set the queue type 
    // the queue do not have reset function
    // so we just recreate it , and it always
    // happens at the scene change( loading stage )
    // so it won't bother us .
    queue_type_.Reset( new QueueType() );
    if( delegate_ptr_.Null() ) {
      delegate_ptr_.Reset( new WorkerThread(queue_type_) );
    } else {
      WorkerThread* wthread = (WorkerThread*)delegate_ptr_.Get();
      wthread->set_queue_type( queue_type_ );
    }
    // Checking the thread handler is empty or not ?
    XASSERT( thread_handler_ptr_.Null() );
    // Create the internal thread handler and run the
    // message loop 
    thread_handler_ptr_ = ThreadManager::CreateXThread( 
      NULL , delegate_ptr_ , thread_name ,debug_name );
    // now everything is ok , so we just need to make this thread running 
    if( thread_handler_ptr_.Null() ) {
      // error has occurred
      queue_type_.Reset();
      WorkerThread* wthread = (WorkerThread*)delegate_ptr_.Get();
      wthread->Clear();
      return false;
    }
    return true;
  }

  template< typename QueueType >
  const TripleResult Worker<QueueType>::Wait() {
    XASSERT( !thread_handler_ptr_.Null() );
    // We do not choose to wait for the queue , instead 
    // we just join for the thread , since the wait for queue
    // may be not that kind of safe , but it is a little bit
    // slow !
    TripleResult ret(thread_handler_ptr_->Join());
    if( ret == true ) {
      // do the clear job 
      thread_handler_ptr_.Reset();
      queue_type_.Reset();
      task_cache_.clear();
      has_post_destroy_request_ = false;
    }
    return ret;
  }

  template< typename QueueType >
  const TripleResult Worker<QueueType>::Wait( size_t ms ) {
    XASSERT( !thread_handler_ptr_.Null() );
    // We do not choose to wait for the queue , instead 
    // we just join for the thread , since the wait for queue
    // may be not that kind of safe , but it is a little bit
    // slow !
    TripleResult ret(thread_handler_ptr_->Join(ms));
    if( ret == true ) {
      // do the clear job 
      thread_handler_ptr_.Reset();
      queue_type_.Reset();
      task_cache_.clear();
      has_post_destroy_request_ = false;
    }
    return ret;
  }

  template< typename QueueType > 
  bool Worker<QueueType>::Destroy( bool post_quit_soon , bool blocking ) {
    has_post_destroy_request_ = true;
    if( post_quit_soon )
      queue_type_->PostQuitSoon();
    else
      queue_type_->PostQuitWhenEmpty();
    if( blocking ) {
      return Wait();
    } 
    return true;
  }

  template< typename QueueType > 
  void Worker<QueueType>::PushTask( const TaskPtr& task , bool delay ) {
    XASSERT( !thread_handler_ptr_.Null() );
    // push the task into the list 
    if( !delay )
      queue_type_->PushTask( task );
    else 
      task_cache_.push_back(task);
  }

  template< typename QueueType >
  Worker<QueueType>::~Worker() {
    // worker stuff !
    // Now we should understand , if this worker has been posted to delete
    // we will have no chance to get the resource again .So we have to 
    // testing if the thread is over or not 
    if( !thread_handler_ptr_.Null() ) {
      // so the thread is still turning on 
      // wait to quit the thread here 
      Destroy( true , true );
      // Loggin the panic information into the
      // log 
      SYS_LOG(PANIC,true,_xT("A worker queue has not been turned off when the worker has been deleted!\n")
        _xT("ThreadName:%s.\n") , thread_handler_ptr_->name().c_str() );
    }
  }
  // Another wrapper for the virtual function calling 
  // This wrapper for the queue type will use the WorkerQueue 
  // as the basic queue holder for the queue instead of 
  // using template class to do so .

  class VirtualWorker : public Allocator {
  public:
    // Construct a virtual worker queue by specifying the
    // worker type tag , using WorkerQueue::QUEUE_TYPE_SINGLE_QUEUE related 
    // tag . 
    bool Dispatch( const int worker_type , const String& thread_name , const char* debug_name );
    // Destroy the specific queue thread and queue 
    bool Destroy( bool post_quit_soon , bool blocking );
    // Waiting stuff
    const TripleResult Wait( size_t ms );
    const TripleResult Wait();
    // Testing if this queue is under the destroy stage
    bool HasPostDestroyRequest() const {
      return has_post_destroy_request_;
    }
    // Push the task into the queue
    void PushTask( const TaskPtr& task , bool delay );
    // Sync the task pointer to the back queue
    void Sync();
    VirtualWorker():has_post_destroy_request_(false){}
    ~VirtualWorker();
  public:
    // Get the queue type tag 
    int queue_type() const {
      XASSERT ( !worker_queue_ptr_.Null() );
      return worker_queue_ptr_->queue_type();
    }
  private:
    class WorkerThread;
    // a local tag to testing if this thread has been sent the post request
    bool has_post_destroy_request_;
    // the local task cache 
    typedef WorkerQueue::TaskPtrList TaskPtrList;
    TaskPtrList task_cache_;
    // the worker queue ptr , WorkerQueue is a virtual base class 
    // using this as the root pointer to contain the specific class
    WorkerQueuePtr worker_queue_ptr_;
    // thread delegate ptr
    ThreadDelegatePtr thread_delegate_ptr_;
    // thread handler ptr
    ThreadHandlerPtr thread_handler_ptr_;
  };




}
}
#endif// XGE_XWORKER_H_